<template>
	<view class="tui-container">
		<view class="tui-upload-box">
			<view class="tui-image-item" :style="{ width: width + 'rpx', height: height + 'rpx' }" v-for="(item, index) in imageList" :key="index">
				<image :src="item.path" class="tui-item-img" :style="{ width: width + 'rpx', height: height + 'rpx' }" @tap.stop="previewImage(index)" mode="aspectFill"></image>

				<view v-if="!forbidDel" class="tui-img-del" @tap.stop="delImage(index)"></view>

				<view v-if="statusArr[index] != 1" class="tui-upload-mask">
					<view v-if="statusArr[index] == 2" class="tui-upload-loading"></view>
					<text class="tui-tips">{{ statusArr[index] == 2 ? '上传中...' : '上传失败' }}</text>
					<view v-if="statusArr[index] == 3" class="tui-mask-btn" @tap.stop="reUpLoad(index)" hover-class="tui-btn-hover" :hover-stay-time="150">重新上传</view>
				</view>
			</view>

			<view v-if="isShowAdd" class="tui-upload-add" :style="{ width: width + 'rpx', height: height + 'rpx' }" @tap="chooseImage">
				<view class="tui-upload-icon tui-icon-plus"></view>
			</view>
		</view>
	</view>
</template>

<script setup>
import { ref, computed, watch, onBeforeMount } from 'vue'

const emit = defineEmits(['remove', 'complete'])

const props = defineProps({
	//展示图片宽度
	width: {
		type: [Number, String],
		default: 220
	},
	//展示图片高度
	height: {
		type: [Number, String],
		default: 220
	},
	//初始化图片路径
	value: {
		type: Array,
		default() {
			return []
		}
	},
	//禁用删除
	forbidDel: {
		type: Boolean,
		default: false
	},
	//禁用添加
	forbidAdd: {
		type: Boolean,
		default: false
	},
	//服务器接口地址。当接口地址为空时，直接返回本地图片地址
	serverUrl: {
		type: String,
		default: ''
	},
	//限制数
	limit: {
		type: Number,
		default: 9
	},
	//original 原图，compressed 压缩图，默认二者都有
	sizeType: {
		type: Array,
		default() {
			return ['original', 'compressed']
		}
	},
	//album 从相册选图，camera 使用相机，默认二者都有。如需直接开相机或直接选相册，请只使用一个选项
	sourceType: {
		type: Array,
		default() {
			return ['album', 'camera']
		}
	},
	//可上传图片类型，默认为空，不限制  Array<String> ['jpg','png','gif']
	imageFormat: {
		type: Array,
		default() {
			return []
		}
	},
	//单张图片大小限制 MB
	size: {
		type: Number,
		default: 4
	},
	//文件对应的key，默认为 file
	fileKeyName: {
		type: String,
		default: 'file'
	},
	//HTTP 请求 Header, header 中不能设置 Referer。
	header: {
		type: Object,
		default() {
			return {}
		}
	},
	//HTTP 请求中其他额外的 form data
	formData: {
		type: Object,
		default() {
			return {}
		}
	},
	//自定义参数
	params: {
		type: [Number, String],
		default: 0
	}
})

//图片地址
const imageList = ref([])

//上传状态：1-上传成功 2-上传中 3-上传失败
const statusArr = ref([])

const isShowAdd = computed(() => {
	let isShow = true
	if (props.forbidAdd || (props.limit && imageList.value.length >= props.limit)) {
		isShow = false
	}
	return isShow
})

watch(
	() => props.value,
	nVal => {
		if (nVal) {
			initImages()
		}
	}
)

onBeforeMount(() => {
	initImages()
})

const initImages = () => {
	statusArr.value = []
	imageList.value = [...props.value]
	for (let item of imageList.value) {
		statusArr.value.push('1')
	}
}

/**
 * @param manual 是否手动上传
 **/
const change = (manual = false) => {
	let status = ~statusArr.value.indexOf('2') ? 2 : 1
	if (status != 2 && ~statusArr.value.indexOf('3')) {
		// 上传失败
		status = 3
	}
	emit('complete', {
		status: status,
		imgArr: imageList.value,
		params: props.params,
		manual: manual
	})
}

// 重新上传
const reUpLoad = index => {
	statusArr.value[index] = '2'
	change()
	uploadImage(index, imageList.value[index].path)
		.then(() => {
			change()
		})
		.catch(() => {
			change()
		})
}

const chooseImage = () => {
	uni.chooseImage({
		count: props.limit - imageList.value.length,
		sizeType: props.sizeType,
		sourceType: props.sourceType,
		success: e => {
			let imageArr = []

			for (let i = 0; i < e.tempFiles.length; i++) {
				let len = imageList.value.length
				if (len >= props.limit) {
					uni.showToast({
						title: `最多可上传${props.limit}张图片`,
						icon: 'none'
					})
					break
				}

				//过滤图片类型
				let path = e.tempFiles[i].path

				if (props.imageFormat.length > 0) {
					let format = ''
					// #ifdef H5
					let type = e.tempFiles[i].type
					format = type.split('/')[1]
					// #endif

					// #ifndef H5
					format = path.split('.')[path.split('.').length - 1]
					// #endif

					if (props.imageFormat.indexOf(format) == -1) {
						let text = `只能上传 ${props.imageFormat.join(',')} 格式图片！`
						uni.showToast({
							title: text,
							icon: 'none'
						})
						continue
					}
				}

				//过滤超出大小限制图片
				let size = e.tempFiles[i].size
				if (props.size * 1024 * 1024 < size) {
					let err = `单张图片大小不能超过：${props.size}MB`
					uni.showToast({
						title: err,
						icon: 'none'
					})
					continue
				}

				imageArr.push({ path, id: '' })
				imageList.value.push({ path, id: '' })
				statusArr.value.push('2')
			}

			// change()

			let start = imageList.value.length - imageArr.length
			for (let j = 0; j < imageArr.length; j++) {
				let index = start + j
				//服务器地址
				if (props.serverUrl) {
					uploadImage(index, imageArr[j].path)
						.then(() => {
							change()
						})
						.catch(() => {
							change()
						})
				} else {
					//无服务器地址则直接返回成功
					statusArr.value[index] = '1'
					change()
				}
			}
		}
	})
}

const uploadImage = (index, url, serverUrl) => {
	return new Promise((resolve, reject) => {
		uni.uploadFile({
			url: props.serverUrl || serverUrl,
			name: props.fileKeyName,
			header: props.header,
			formData: props.formData,
			filePath: url,
			success: res => {
				if (res.statusCode == 200) {
					//返回结果 此处需要按接口实际返回进行修改
					let d = JSON.parse(res.data.replace(/\ufeff/g, '') || '{}')
					console.log('uploadFile: ', d)
					//判断code，以实际接口规范判断
					if (d.meta.code === 0) {
						// 上传成功 d.url 为上传后图片地址，以实际接口返回为准
						if (d.data) {
							imageList.value[index].id = d.data
						}
						statusArr.value[index] = d.data ? '1' : '3'
					} else {
						// 上传失败
						statusArr.value[index] = '3'
					}
					resolve(index)
				} else {
					statusArr.value[index] = '3'
					reject(index)
				}
			},
			fail: res => {
				statusArr.value[index] = '3'
				reject(index)
			}
		})
	})
}

const delImage = index => {
	imageList.value.splice(index, 1)
	statusArr.value.splice(index, 1)

	emit('remove', {
		index: index,
		params: props.params
	})

	change()
}

const previewImage = index => {
	if (!imageList.value.length) return
	uni.previewImage({
		current: imageList.value[index].path,
		loop: true,
		urls: imageList.value.map(item => item.path)
	})
}

/**
 * 当属性serverUrl传空时，父级调用该方法一次性上传所有图片
 * @param serverUrl 服务器接口地址
 **/
const uploadAllImage = serverUrl => {
	if (!serverUrl) {
		uni.showToast({
			title: '服务器接口地址不能为空！',
			icon: 'none'
		})
		return
	}
	let imageArr = [...imageList.value]
	const len = imageArr.length
	for (let i = 0; i < len; i++) {
		//如果是服务器地址图片则无需再次上传
		if (imageArr[i].path.startsWith('https')) {
			continue
		} else {
			statusArr.value[i] = '2'
			uploadImage(i, imageArr[i].path, serverUrl)
				.then(() => {
					if (i === len - 1) {
						change(true)
					}
				})
				.catch(() => {
					if (i === len - 1) {
						change(true)
					}
				})
		}
	}
}
</script>

<style lang="scss" scoped>
@font-face {
	font-family: 'tuiUpload';
	src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAATcAA0AAAAAByQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEwAAAABoAAAAciR52BUdERUYAAASgAAAAHgAAAB4AKQALT1MvMgAAAaAAAABCAAAAVjxvR/tjbWFwAAAB+AAAAEUAAAFK5ibpuGdhc3AAAASYAAAACAAAAAj//wADZ2x5ZgAAAkwAAADXAAABAAmNjcZoZWFkAAABMAAAAC8AAAA2FpiS+WhoZWEAAAFgAAAAHQAAACQH3QOFaG10eAAAAeQAAAARAAAAEgwAACBsb2NhAAACQAAAAAwAAAAMAEoAgG1heHAAAAGAAAAAHwAAACABEgA2bmFtZQAAAyQAAAFJAAACiCnmEVVwb3N0AAAEcAAAACgAAAA6OMUs4HjaY2BkYGAAYo3boY/i+W2+MnCzMIDAzb3qdQj6fwPzf+YGIJeDgQkkCgA/KAtvAHjaY2BkYGBu+N/AEMPCAALM/xkYGVABCwBZ4wNrAAAAeNpjYGRgYGBl0GJgZgABJiDmAkIGhv9gPgMADTABSQB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ9xMjf8b2CIYW5gaAAKM4LkANt9C+UAAHjaY2GAABYIVmBgAAAA+gAtAAAAeNpjYGBgZoBgGQZGBhBwAfIYwXwWBg0gzQakGRmYnjE+4/z/n4EBQksxSf6GqgcCRjYGOIeRCUgwMaACRoZhDwCiLwmoAAAAAAAAAAAAAAAASgCAeNpdjkFKw0AARf/vkIR0BkPayWRKQZtYY90ohJju2kOIbtz0KD1HVm50UfEmWXoAr9ADOHFARHHzeY//Fx8Ci+FJfIgdJFa4AhgiMshbrCuIsLxhFJZVs+Vl1bT1GddtbXTC3OhohN4dg4BJ3zMJAnccyfm468ZzHXddrH9ZKbHzdf9n/vkY/xv9sPQXgGEvBrHHwst5kTbXLE+YpYVPkxepPmW94W16UbdNJd6f3SAzo5W7m1jaKd+8ZZIvk5nlKw9SK6Wle7BLS3f/bTzQLmfAF2T1NsQAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMGiTIxMjMxsKak5qSWpbFmZiRmJ+QAmgAUIAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMABAABAAQAAAACAAAAAHjaY2BgYGQAgqtL1DlA9M296nUwGgA+8QYgAAA=)
		format('woff');
	font-weight: normal;
	font-style: normal;
}

.tui-upload-icon {
	font-family: 'tuiUpload' !important;
	font-style: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	padding: 10rpx;
}

.tui-icon-delete:before {
	content: '\e601';
}

.tui-icon-plus:before {
	content: '\e609';
}

.tui-upload-box {
	width: 100%;
	display: flex;
	flex-wrap: wrap;
}

.tui-upload-add {
	font-size: 68rpx;
	font-weight: 100;
	color: #888;
	background-color: #f7f7f7;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
}

.tui-image-item {
	position: relative;
	margin-right: 20rpx;
	margin-bottom: 20rpx;
}

.tui-image-item:nth-of-type(3n) {
	margin-right: 0;
}

.tui-item-img {
	display: block;
}

.tui-img-del {
	width: 36rpx;
	height: 36rpx;
	position: absolute;
	right: -12rpx;
	top: -12rpx;
	background-color: #eb0909;
	border-radius: 50%;
	color: white;
	font-size: 34rpx;
	z-index: 999;
}

.tui-img-del::before {
	content: '';
	width: 16rpx;
	height: 1px;
	position: absolute;
	left: 10rpx;
	top: 18rpx;
	background-color: #fff;
}

.tui-upload-mask {
	width: 100%;
	height: 100%;
	position: absolute;
	left: 0;
	top: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 40rpx 0;
	box-sizing: border-box;
	background-color: rgba(0, 0, 0, 0.6);
}

.tui-upload-loading {
	width: 28rpx;
	height: 28rpx;
	border-radius: 50%;
	border: 2px solid;
	border-color: #b2b2b2 #b2b2b2 #b2b2b2 #fff;
	animation: tui-rotate 0.7s linear infinite;
}

@keyframes tui-rotate {
	0% {
		transform: rotate(0);
	}

	100% {
		transform: rotate(360deg);
	}
}

.tui-tips {
	font-size: 26rpx;
	color: #fff;
}

.tui-mask-btn {
	padding: 4rpx 16rpx;
	border-radius: 40rpx;
	text-align: center;
	font-size: 24rpx;
	color: #fff;
	border: 1rpx solid #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	margin-top: 26rpx;
}

.tui-btn-hover {
	opacity: 0.8;
}
</style>
